package com.amin.ms3d;

import android.opengl.GLES32;
import android.opengl.Matrix;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;

import com.graphics.element.AbsSceneNode;
import com.math3d.Mat4;
import com.math3d.Quaternion;
import com.math3d.Vector3f;
import com.math3d.Vector3fv;
import com.math3d.Vector4fv;
import com.system.GLLog;
import com.system.Shader;
import com.tools.GLBufferTools;
import com.tools.SizeOf;
import com.tools.TextureTools;

import org.w3c.dom.Text;

import java.lang.reflect.Array;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.microedition.khronos.opengles.GL;

/**
 * MS3D模型
 * @Author: clm
 * @Date:2018年11月12日13:47:24
 */
public class MS3DObj extends AbsSceneNode{
    /**
     * 点
     * @author Administrator
     *
     */
    public static class MS3DVecter{
        public float x, y, z;

        public MS3DVecter(float x, float y, float z) {
            super();
            this.x = x;
            this.y = y;
            this.z = z;
        }

    }
    /**
     * MS3D顶点数据
     * @author Administrator
     *
     */
    public static class MS3DVertex{
        //编辑器用标志(1个字节)
        public int mFlags;
        //顶点坐标(共12个字节)
        public float mX, mY, mZ;
        //骨骼id(1个字节,-1,没有骨骼)
        public int mBoneID;
        //保留,未使用(1个字节)
        public int mUnused;
        @Override
        public String toString() {
            return "MS3DVertex [mFlags=" + mFlags + ", mX=" + mX + ", mY="
                    + mY + ", mZ=" + mZ + ", mBoneID=" + mBoneID
                    + ", mUnused=" + mUnused + "]";
        }
    }
    /**
     * MS3D图元数据
     * @author Administrator
     *
     */
    public static class MS3DFace{
        //编辑器用标志(2个字节)
        public short mFlags;
        //顶点索引(每2个字节表示一个索引),由于ms3d是三角形图元,因此每个三角形3个索引
        public int[] mVertexIndexs;
        //法线(每4个字节为一个值,12个字节为一个法线)
        public MS3DVecter[] mNormals;
        //纹理坐标(每4个字节为一个值,存储方式为:6个float依次代表u1,u2,u3,v1,v2,v3)
        public float[][] mUvs;
        //网格/组的光滑组索引(1个字节)
        public int mSmoothing;
        //网格/组的索引,用于使用不同材质(1个字节)
        public int mGroup;
        public MS3DFace(){
            mVertexIndexs = new int[3];
            mNormals = new MS3DVecter[3];
            mUvs = new float[2][3];
        }
    }
    /**
     * 边缘组
     * @author Administrator
     *
     */
    public static class MS3DEdge{
        //2*2个字节
        public int mEdgeIndices[];
        public MS3DEdge(){
            mEdgeIndices = new int[2];
        }
    }
    /**
     * 网格
     * @author Administrator
     *
     */
    public static class MS3DMesh{
        //编辑器用标志(1个字节)
        public int mFlags;
        //网格名称(32个字节)
        public char mName[];
        //图元数量(2个字节)
        public int mNumTris;
        //图元索引(2个字节为一个值)
        public int mFaceIndexs[];
        //材质索引(1个字节,-1表示没有材质)
        public int mMaterial;
        public MS3DMesh(){
            mName = new char[32];
        }
    }
    /**
     * 材质
     * @author Administrator
     *
     */
    public static class MS3DMaterial{
        //材质名称(32个字节)
        public char mName[];
        //环境光(4 * 4个字节,4个元素)
        public float mAmbient[];
        //漫反射光(4 * 4个字节)
        public float mDiffuse[];
        //镜面反射(4 * 4个字节)
        public float mSpecular[];
        //自发光(4 * 4个字节)
        public float mEmissive[];
        //高光强度(4个字节)
        public float mShine;
        //透明度(4个字节)
        public float mTransparency;
        //未使用(1个字节)
        public char mMode;
        //纹理文件名(128个字节)
        public char mTexture[];
        //透明纹理文件名(128个字节)
        public char mAlpha[];
        //自身索引
        public char mId;
        public char[] mComment;
        public MS3DMaterial(){
            mName = new char[32];
            mAmbient = new float[4];
            mDiffuse = new float[4];
            mSpecular = new float[4];
            mEmissive = new float[4];
            mTexture = new char[128];
            mAlpha = new char[128];
            mComment = new char[11];
        }
        @Override
        public String toString() {
            return "MS3DMaterial [mName=" + String.valueOf(mName).trim()
                    + ", mAmbient=" + Arrays.toString(mAmbient)
                    + ", mDiffuse=" + Arrays.toString(mDiffuse)
                    + ", mSpecular=" + Arrays.toString(mSpecular)
                    + ", mEmissive=" + Arrays.toString(mEmissive)
                    + ", mShine=" + mShine + ", mTransparency="
                    + mTransparency + ", mMode=" + mMode + ", mTexture="
                    + String.valueOf(mTexture).trim() + ", mAlpha="
                    + String.valueOf(mAlpha).trim() + ", mId="
                    + mId + ", mComment=" + String.valueOf(mComment).trim() + "]";
        }

    }
    /**
     * 关键帧
     * @author Administrator
     *
     */
    public static class MS3DKeyFrame{
        //时间长度(4个字节)
        public float mTime;
        //变换参数,一个三维向量(3 * 4个字节)
        //表示一个旋转或平移。如果是表示平移，那三个值分别是X,Y,Z轴上的平移值；如果是表示旋转，则这三个值表示了旋转的欧拉角
        public float mParams[];
        //如果是旋转帧，则提前计算好四元素
        public Quaternion mQuaternion;
        //如果是平移帧,则提前计算好向量
        public Vector4fv mVector4fv;
        public MS3DKeyFrame(){
            mParams = new float[3];
        }

        /**
         * 计算四元素
         */
        public final void scaleQuat4f(){
            mQuaternion = Quaternion.eulerAnglesToQuaternion(mParams[0], mParams[1], mParams[2]);
        }

        /**
         * 计算向量
         */
        public final void scaleVec(){
            mVector4fv = new Vector4fv(mParams[0], mParams[1], mParams[2], 1.0f);
        }
        @Override
        public String toString() {
            return "MS3DKeyFrame [mTime=" + mTime + ", mParams="
                    + Arrays.toString(mParams) + "]";
        }
    }
    /**
     * 骨骼
     * @author Administrator
     *
     */
    public static class MS3DJoint{
        //编辑器标志(1个字节)
        public int mFlags;
        //joint名字(32个字节)
        public char mName[];
        //joint父joint名字(32个字节)
        public char mParent[];
        public String mParentStr;
        public MS3DJoint mParentJoint;
        //初始旋转量(3 * 4个字节,欧拉角)
        public float mRotation[];
        //初始位置(3 * 4个字节)
        public float mPosition[];
        //旋转帧数量(2个字节)
        public int mNumRotFrames;
        //平移帧数量(2个字节)
        public int mNumTransFrames;
        //旋转帧
        public MS3DKeyFrame mRotKeyFrames[];
        //平移帧
        public MS3DKeyFrame mTransKeyFrames[];
        //绝对矩阵
        public Mat4 mAbsMat4;
        //相对矩阵
        public Mat4 mRelMat4;
        //变换矩阵(最终应用这个矩阵)
        public Mat4 mTransformMat4;
        //临时缓存矩阵
        private Mat4 mTemp;
        public MS3DJoint(){
            mName = new char[32];
            mParent = new char[32];
            mRotation = new float[3];
            mPosition = new float[3];
            mAbsMat4 = new Mat4();
            mRelMat4 = new Mat4();
            mTransformMat4 = new Mat4();
            mTemp = new Mat4();
        }

        /**
         * 通过外部统一初始化这个矩阵(因为相对变换需要用于构造绝对变换),为了防止父节点的绝对变换矩阵未初始化<br/>
         * 所以需要在这里通过外部统一初始化所有节点的相对变换矩阵
         */
        public final void initRelativeMat(){
            //设置相对矩阵
            //旋转
//            Matrix.setRotateEulerM(mRelMat4.mMat4, 0, mRotation[0], mRotation[1], mRotation[2]);
            mRelMat4.mMat4 = Quaternion.converToMat4f(Quaternion.eulerAnglesToQuaternion(mRotation[0], mRotation[1], mRotation[2]));
            //平移
//            Matrix.translateM(mRelMat4.mMat4, 0, mPosition[0], mPosition[1], mPosition[2]);
            mRelMat4.setTranslate(mPosition);
            GLLog.loge("name:" + String.valueOf(mName).trim());
            GLLog.loge("mRotation:" + Arrays.toString(mRotation));
            GLLog.loge("mPosition:" + Arrays.toString(mPosition));
        }

        /**
         * 初始化矩阵
         */
        public final void initMAT4(List<MS3DJoint> joints){
            //更新相对矩阵
            for(MS3DJoint joint : joints){
                joint.initRelativeMat();
            }
            if(mParent != null){
                mParentStr = String.valueOf(mParent).trim();
            }
            if(TextUtils.isEmpty(mParentStr)){
                //无父节点
                mAbsMat4.setTo(mRelMat4);
            }
            else{
                //有父节点
                //找到父节点
                for(MS3DJoint parent : joints){
                    if(String.valueOf(parent.mName).trim().equals(mParentStr)){
                        mParentJoint = parent;
                        //先进行相对矩阵变换,再应用父变换
//                        Matrix.multiplyMV(result.getVec(), 0, mCameraRotateMat4, 0, dir.getVec(), 0);
                        Mat4 result = new Mat4();
                        Matrix.multiplyMM(result.mMat4, 0, mRelMat4.mMat4, 0, parent.mAbsMat4.mMat4, 0);
                        mAbsMat4.setTo(result);
                        break;
                    }
                }
            }
            GLLog.loge("joint:" + String.valueOf(mName).trim());
            GLLog.loge("rotate:" + Arrays.toString(mRotation) + ";position:" + Arrays.toString(mPosition));
//            GLLog.loge("平移帧:");
//            for(int i = 0;i < mNumTransFrames;i++){
//                GLLog.loge(Arrays.toString(mTransKeyFrames[i].mParams));
//            }
//            GLLog.loge("旋转帧:");
//            for(int i = 0;i < mNumRotFrames;i++){
//                GLLog.loge(Arrays.toString(mRotKeyFrames[i].mParams));
//                GLLog.loge("四元素:" + mRotKeyFrames[i].mQuaternion.toString());
//                GLLog.loge("矩阵" + Arrays.toString(Quaternion.converToMat4f(mRotKeyFrames[i].mQuaternion)));
//            }
            GLLog.loge("rel:" + Arrays.toString(mRelMat4.mMat4) + ",abs:" + Arrays.toString(mAbsMat4.mMat4));
        }

        /**
         * 插值计算旋转矩阵
         * @param time
         */
        public final Mat4 rotate(float time){
            mTemp.normalize();
            int keyFrameIndex = 0;
            while(keyFrameIndex < mNumRotFrames && mRotKeyFrames[keyFrameIndex].mTime < time)
                keyFrameIndex++;
            if(keyFrameIndex == 0){
//                if(TextUtils.isEmpty(mParentStr))
//                GLLog.loge("取0");
                //Matrix.setRotateEulerM(mTemp.mMat4, 0, mRotKeyFrames[keyFrameIndex].mParams[0], mRotKeyFrames[keyFrameIndex].mParams[1], mRotKeyFrames[keyFrameIndex].mParams[2]);
                mTemp.mMat4 = Quaternion.converToMat4f(mRotKeyFrames[keyFrameIndex].mQuaternion);
            }
            else if(keyFrameIndex == mNumRotFrames){
                keyFrameIndex -= 1;
//                if(TextUtils.isEmpty(mParentStr))
//                GLLog.loge("取1");
                //Matrix.setRotateEulerM(mTemp.mMat4, 0, mRotKeyFrames[keyFrameIndex].mParams[0], mRotKeyFrames[keyFrameIndex].mParams[1], mRotKeyFrames[keyFrameIndex].mParams[2]);
                mTemp.mMat4 = Quaternion.converToMat4f(mRotKeyFrames[keyFrameIndex].mQuaternion);
            }
            else{
                //找到临近两帧
                MS3DKeyFrame left = mRotKeyFrames[keyFrameIndex - 1];
                MS3DKeyFrame right = mRotKeyFrames[keyFrameIndex];
                if(TextUtils.isEmpty(mParentStr)){
                    if(keyFrameIndex == mNumRotFrames - 1){
                        //
                    }
                }
                //插值计算当前帧
                Quaternion quaternion = Quaternion.slerp(left.mQuaternion, right.mQuaternion, (time - left.mTime) / (right.mTime - left.mTime));
                mTemp.mMat4 = Quaternion.converToMat4f(quaternion);
            }
            return mTemp;
        }

        /**
         * 插值计算平移部分
         * @param time
         * @return
         */
        public final Vector4fv translate(float time){
            Vector4fv v = null;
            int keyFrameIndex = 0;
            while(keyFrameIndex < mNumTransFrames && mTransKeyFrames[keyFrameIndex].mTime < time)
                keyFrameIndex++;
            if(keyFrameIndex == 0){
                v = new Vector4fv(mTransKeyFrames[keyFrameIndex].mParams[0], mTransKeyFrames[keyFrameIndex].mParams[1], mTransKeyFrames[keyFrameIndex].mParams[2], 1.0f);
            }
            else if(keyFrameIndex == mNumTransFrames){
                keyFrameIndex -= 1;
                v = new Vector4fv(mTransKeyFrames[keyFrameIndex].mParams[0], mTransKeyFrames[keyFrameIndex].mParams[1], mTransKeyFrames[keyFrameIndex].mParams[2], 1.0f);
            }
            else{
                MS3DKeyFrame left = mTransKeyFrames[keyFrameIndex - 1];
                MS3DKeyFrame right = mTransKeyFrames[keyFrameIndex];
                v = Vector4fv.inter(left.mVector4fv, right.mVector4fv, (time - left.mTime) / (right.mTime - left.mTime));
            }
            return v;
        }
        @Override
        public String toString() {
            return "MS3DJoint [mFlags=" + mFlags + ", mName="
                    + String.valueOf(mName).trim() + ", mParent="
                    + String.valueOf(mParent).trim() + ", mRotation="
                    + Arrays.toString(mRotation) + ", mPosition="
                    + Arrays.toString(mPosition) + ", mNumRotFrames="
                    + mNumRotFrames + ", mNumTransFrames="
                    + mNumTransFrames + ", mRotKeyFrames="
                    + Arrays.toString(mRotKeyFrames) + ", mTransKeyFrames="
                    + Arrays.toString(mTransKeyFrames) + "]";
        }
    }

    /**
     * 渲染数据
     */
    public class MS3DRenderData{
        public int mVAO;
        public int mTexID[];
        public int mVerCount;

        public MS3DRenderData(int VAO, int[] texID, int verCount) {
            mVAO = VAO;
            mTexID = texID;
            mVerCount = verCount;
        }
    }
    public final static float S_1000L = 1.0f / 10000.0f;
    //版本id
    public String mVertsionID;
    //顶点数据
    public List<MS3DVertex> mVertexs;
    public MS3DVertex mVertexArray[];
    //图元数据
    public List<MS3DFace> mFaces;
    public MS3DFace mFaceArray[];
    //网格数据
    public List<MS3DMesh> mMeshs;
    public MS3DMesh mMeshArray[];
    //材质数据
    public List<MS3DMaterial> mMaterials;
    public MS3DMaterial mMaterialArray[];
    //骨骼数据
    public List<MS3DJoint> mJoints;
    public MS3DJoint mJointArray[];
    //动画播放帧率
    public float mAnimationFPS;
    //当前时间
    public float mCurrentTime;
    //总帧树
    public int mTotalFrames;
    //总时间
    public float mTotalTime;
    //文件路径
    private String mPath;
    //着色器
    private Shader mShader;
    //存放骨骼id
    private int mBoneID[];
    //渲染集合数组
    private MS3DRenderData mMS3DRenderData[];
    /**
     * 初始化
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public final void setup(){
        //转换数据为数组格式保存一份
        mVertexArray = new MS3DVertex[mVertexs.size()];
        mVertexs.toArray(mVertexArray);
        mMeshArray = new MS3DMesh[mMeshs.size()];
        mMeshs.toArray(mMeshArray);
        mMaterialArray = new MS3DMaterial[mMaterials.size()];
        mMaterials.toArray(mMaterialArray);
        mJointArray = new MS3DJoint[mJoints.size()];
//        Collections.reverse(mJoints);
        mJoints.toArray(mJointArray);
        //计算总帧时间
        GLLog.loge("总时间:" + mTotalTime + ",总帧数:" + mTotalFrames);
        initShader();
        initJoints();
        initRenderData();
    }

    /**
     * 初始化骨骼
     */
    public final void initJoints(){
        GLES32.glUseProgram(mShader.mShaderProgram);
        int i = 0;
        mBoneID = new int[256];
        for(MS3DJoint joint : mJoints){
            GLLog.loge(String.valueOf(joint.mName).trim() + ",帧:" + joint.mNumRotFrames + ":" + joint.mNumTransFrames);
            mBoneID[i] = GLES32.glGetUniformLocation(mShader.mShaderProgram, "joints.matrix[" + i + "]");
            i++;
            if(joint.mNumRotFrames > 0){
                for(MS3DKeyFrame rotKeyFrame : joint.mRotKeyFrames){
                    rotKeyFrame.scaleQuat4f();
                }
            }
            if(joint.mNumTransFrames > 0){
                for(MS3DKeyFrame tranKeyFrame : joint.mTransKeyFrames){
                    tranKeyFrame.scaleVec();
                }
            }
            joint.initMAT4(mJoints);
        }
        GLES32.glUseProgram(0);
    }
    /**
     * 加载着色器
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public final void initShader(){
        mShader = new Shader("ms3d_vs.glsl", "texture_base_fs.glsl");
        GLES32.glUseProgram(mShader.mShaderProgram);
        GLES32.glUniformBlockBinding(mShader.mShaderProgram, GLES32.glGetUniformBlockIndex(mShader.mShaderProgram, "MATRIX"), 0x001);
        GLES32.glUseProgram(0);
    }

    /**
     * 初始化渲染数据
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public final void initRenderData(){
        List<MS3DRenderData> renderData = new ArrayList<>();
        Map<String, Integer> textIDs = new HashMap<>();
        //遍历所有网格
        MS3DMesh mesh = null;
        MS3DFace face = null;
        MS3DVertex vertex = null;
        MS3DMaterial ms3DMaterial = null;
        for(int i = 0;i < mMeshs.size();i++){
            mesh = mMeshs.get(i);
            //每个面有三个顶点,每个顶点三个浮点数
            float[] vertexFloat = new float[mesh.mNumTris * 3 * 3];
            //每个面有三个顶点,每个顶点两个浮点数
            float[] uvs = new float[mesh.mNumTris * 3 * 2];
            //法线(同理)
            float[] normals = new float[mesh.mNumTris * 3 * 3];
            //骨骼索引,每个顶点一个索引
            int[] boneIndex = new int[mesh.mNumTris * 3];
            int fi = 0;
            int uvi = 0;
            int ni = 0;
            int bi = 0;
            //遍历该网格所有图元数据
            for(int f = 0;f < mesh.mNumTris;f++){
                face = mFaces.get(mesh.mFaceIndexs[f]);
                //取出当前图元的顶点数据(位置,uv,法线)
                vertex = mVertexs.get(face.mVertexIndexs[0]);
                vertexFloat[fi++] = vertex.mX;
                vertexFloat[fi++] = vertex.mY;
                vertexFloat[fi++] = vertex.mZ;
                uvs[uvi++] = face.mUvs[0][0];
                uvs[uvi++] = face.mUvs[1][0];
                normals[ni++] = face.mNormals[0].x;
                normals[ni++] = face.mNormals[0].y;
                normals[ni++] = face.mNormals[0].z;
                boneIndex[bi++] = vertex.mBoneID;
//                boneIndex[bi++] = vertex.mBoneID;
                vertex = mVertexs.get(face.mVertexIndexs[1]);
                vertexFloat[fi++] = vertex.mX;
                vertexFloat[fi++] = vertex.mY;
                vertexFloat[fi++] = vertex.mZ;
                uvs[uvi++] = face.mUvs[0][1];
                uvs[uvi++] = face.mUvs[1][1];
                normals[ni++] = face.mNormals[1].x;
                normals[ni++] = face.mNormals[1].y;
                normals[ni++] = face.mNormals[1].z;
                boneIndex[bi++] = vertex.mBoneID;
//                boneIndex[bi++] = vertex.mBoneID;
                vertex = mVertexs.get(face.mVertexIndexs[2]);
                vertexFloat[fi++] = vertex.mX;
                vertexFloat[fi++] = vertex.mY;
                vertexFloat[fi++] = vertex.mZ;
                uvs[uvi++] = face.mUvs[0][2];
                uvs[uvi++] = face.mUvs[1][2];
                normals[ni++] = face.mNormals[2].x;
                normals[ni++] = face.mNormals[2].y;
                normals[ni++] = face.mNormals[2].z;
                boneIndex[bi++] = vertex.mBoneID;
//                boneIndex[bi++] = vertex.mBoneID;
            }
            //顶点缓存
            int vao[] = new int[1];
            int vbo[] = new int[1];
            FloatBuffer vFB = GLBufferTools.getFloatBuffer(vertexFloat);
            FloatBuffer uvFB = GLBufferTools.getFloatBuffer(uvs);
            FloatBuffer nFB = GLBufferTools.getFloatBuffer(normals);
            IntBuffer bFB = GLBufferTools.getIntBuffer(boneIndex);
            GLLog.loge("长度:" + boneIndex.length + ";boneIndex:" + Arrays.toString(boneIndex));
            //GLLog.loge("顶点数量:" + vertexFloat.length / 3 + "，顶点数据:" + Arrays.toString(vertexFloat));
            GLES32.glGenVertexArrays(1, vao, 0);
            GLES32.glGenBuffers(1, vbo, 0);
            GLES32.glBindVertexArray(vao[0]);
            GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, vbo[0]);
            GLES32.glBufferData(GLES32.GL_ARRAY_BUFFER, (vFB.limit() + uvFB.limit() + nFB.limit() + bFB.limit()) * SizeOf.S_FLOAT_SIZE, null, GLES32.GL_STATIC_DRAW);
            GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, 0, vFB.limit() * SizeOf.S_FLOAT_SIZE, vFB);
            GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, vFB.limit() * SizeOf.S_FLOAT_SIZE, uvFB.limit() * SizeOf.S_FLOAT_SIZE, uvFB);
            GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, (vFB.limit() + uvFB.limit()) * SizeOf.S_FLOAT_SIZE, nFB.limit() * SizeOf.S_FLOAT_SIZE, nFB);
            GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, (vFB.limit() + uvFB.limit() + nFB.limit()) * SizeOf.S_FLOAT_SIZE, bFB.limit() * SizeOf.S_INT_SIZE, bFB);
            GLES32.glVertexAttribPointer(0x001, 3, GLES32.GL_FLOAT, false, 3 * SizeOf.S_FLOAT_SIZE, 0);
            GLES32.glEnableVertexAttribArray(0x001);
            GLES32.glVertexAttribPointer(0x002, 2, GLES32.GL_FLOAT, false, 2 * SizeOf.S_FLOAT_SIZE, vFB.limit() * SizeOf.S_FLOAT_SIZE);
            GLES32.glEnableVertexAttribArray(0x002);
            GLES32.glVertexAttribPointer(0x003, 3, GLES32.GL_FLOAT, false, 3 * SizeOf.S_FLOAT_SIZE, (vFB.limit() + uvFB.limit()) * SizeOf.S_FLOAT_SIZE);
            GLES32.glEnableVertexAttribArray(0x003);
            GLES32.glVertexAttribPointer(0x004, 1, GLES32.GL_INT, false, 1 * SizeOf.S_INT_SIZE, (vFB.limit() + uvFB.limit() + nFB.limit()) * SizeOf.S_FLOAT_SIZE);
            GLES32.glEnableVertexAttribArray(0x004);
            GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, 0);
            GLES32.glBindVertexArray(0);
            //材质着色数据
            ms3DMaterial = mMaterials.get(mesh.mMaterial);
            String textureFilename = formTextureFilename(String.valueOf(ms3DMaterial.mTexture));
            int textID = -1;
            if(textIDs.keySet().contains(textureFilename)){
                textID = textIDs.get(textureFilename);
            }
            else{
                textID = TextureTools.genSimplerTexture(GLES32.GL_TEXTURE_2D, textureFilename);
                textIDs.put(textureFilename, textID);
            }
            GLES32.glUseProgram(mShader.mShaderProgram);
            GLES32.glUniform1i(GLES32.glGetUniformLocation(mShader.mShaderProgram, "text0"), 0);
            GLES32.glUseProgram(0);
            //创建渲染数据
            MS3DRenderData ms3DRenderData = new MS3DRenderData(vao[0], new int[]{textID}, mesh.mNumTris * 3);
            renderData.add(ms3DRenderData);
        }
        mMS3DRenderData = new MS3DRenderData[renderData.size()];
        renderData.toArray(mMS3DRenderData);
    }

    /**
     * 格式化纹理文件路径
     * @param texture
     * @return
     */
    public final String formTextureFilename(String texture){
//        if(texture.contains("\\"))
//            texture = texture.substring(texture.lastIndexOf("\\") + 1, texture.length());
//        else if(texture.contains("/"))
//            texture = texture.substring(texture.lastIndexOf("/") + 1, texture.length());
        GLLog.loge("原纹理:" + texture);
        String fileLast = "";
        if(texture.contains("jpg")){
            fileLast = "jpg";
        }
        else if(texture.contains("png")){
            fileLast = "png";
        }
        else if(texture.contains("bmp")){
            fileLast = "bmp";
        }
        //这里待完善,暂时为了测试,写死dog
        texture = texture.substring(0, texture.indexOf("."));
//        texture = "dog";
        if(texture.contains("\\")){
            StringBuffer sb = new StringBuffer();
            do{
                sb.append(texture.substring(0, texture.indexOf("\\")) + ",");
                texture = texture.substring(texture.indexOf("\\") + 1, texture.length());
            }while(texture.contains("\\"));
            texture = sb.toString().replace(",", "/") + texture;
        }
        if(texture.contains(":")){
            texture = texture.substring(texture.indexOf(":") + 1, texture.length());
            if(texture.indexOf("/") == 0){
                texture = texture.substring(1, texture.length());
            }
        }
        texture = texture + "." + fileLast;
        return mPath + texture;
    }
    /**
     * 更新
     * @param time
     */
    @Override
    public final void update(float time){
        super.update(time);
        GLES32.glUseProgram(mShader.mShaderProgram);
        mCurrentTime += time * S_1000L;
        if(mCurrentTime > mTotalTime){
            mCurrentTime = 0.0f;
        }
        mCurrentTime = 0.0f;
//        GLLog.loge("mCurrentTime:" + mCurrentTime);
        MS3DJoint joint = null;
        //更新骨骼
        for(int i = 0;i < mJoints.size();i++){
            joint = mJoints.get(i);
            //这里暂时先测试旋转部分
//            joint.mTransformMat4.normalize();
            if(joint.mNumRotFrames == 0 || joint.mNumTransFrames == 0){
                joint.mTransformMat4.setTo(joint.mAbsMat4);
                //提交骨骼数据到gpu
                GLES32.glUniformMatrix4fv(mBoneID[i], 1, false, joint.mTransformMat4.getFloatBuffer());
                continue;
            }
            //更新骨骼变换
            Mat4 m = joint.rotate(mCurrentTime);
            m.setTranslate(joint.translate(mCurrentTime).getVec());
            Mat4 mr = new Mat4();
            //x自生矩阵
            Matrix.multiplyMM(mr.mMat4, 0, m.mMat4, 0, joint.mRelMat4.mMat4, 0);
//            GLLog.loge("结果矩阵:" + Arrays.toString(mr.mMat4));
            if(!TextUtils.isEmpty(joint.mParentStr)){
//                GLLog.loge("joint:" + String.valueOf(joint.mName).trim() + ";父节点:" + joint.mParentStr + ",为null?" + joint.mParentJoint);
                //x父变换
                Matrix.multiplyMM(joint.mTransformMat4.mMat4, 0, mr.mMat4, 0, joint.mParentJoint.mTransformMat4.mMat4, 0);
//                GLLog.loge("joint:" + String.valueOf(joint.mName).trim() + "父节点:" + joint.mParentStr + ",变换矩阵:" + Arrays.toString(joint.mTransformMat4.mMat4));
            }
            else{
                joint.mTransformMat4.setTo(mr);
//                GLLog.loge(mBoneID[i] + ";joint:" + String.valueOf(joint.mName).trim() + ",变换矩阵:" + Arrays.toString(joint.mTransformMat4.mMat4));
            }
//            m.normalize();
//            Matrix.translateM(m.mMat4, 0, 100 * (mCurrentTime), 0, 0);
//            GLLog.loge("当前时间:" + mCurrentTime + "旋转变换:" + Arrays.toString(m.mMat4));
            //提交骨骼数据到gpu
//            GLLog.loge("i = " + i);
            GLES32.glUniformMatrix4fv(mBoneID[i], 1, false, joint.mTransformMat4.getFloatBuffer());
//            GLES32.glUniformMatrix4fv(mBoneID[2], 1, false, m.getFloatBuffer());
//            GLLog.loge("骨骼id:" + String.valueOf(joint.mName).trim() + ";变换矩阵:" + Arrays.toString(joint.mTransformMat4.mMat4));
        }
        GLES32.glUseProgram(0);
    }

    /**
     * 查找最靠近指定时间的关键帧
     * @param time
     * @param flag  -1表示查找比当前时间小的最接近的关键帧,0表示查找比当前时间大的最接近的关键帧
     * @return
     */
    private final MS3DKeyFrame findKeyFrame(float time, int flag){
        MS3DKeyFrame keyFrame = null;
        return keyFrame;
    }

    public MS3DObj(String name) {
        super(name);
        mPath = "";
    }

    /**
     * 加载MS3D
     * @param filename
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public final void loadMS3D(String filename){
        if(filename.contains("/")){
            mPath = filename.substring(0, filename.lastIndexOf("/")) + "/";
//            GLLog.loge("path : " + mPath + ",filename : " + filename);
        }
        MS3DReader.loadMS3D(filename, this);
        setup();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void render(float exTime) {
        super.render(exTime);
        //shader
        GLES32.glUseProgram(mShader.mShaderProgram);
        for(MS3DRenderData renderData : mMS3DRenderData){
            for(int i = 0;i < renderData.mTexID.length;i++){
                GLES32.glActiveTexture(GLES32.GL_TEXTURE0 + i);
                GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, renderData.mTexID[i]);
            }
            GLES32.glBindVertexArray(renderData.mVAO);
            GLES32.glDrawArrays(GLES32.GL_TRIANGLES, 0, renderData.mVerCount);
            GLES32.glBindVertexArray(0);
            for(int i = 0;i < renderData.mTexID.length;i++){
                GLES32.glActiveTexture(GLES32.GL_TEXTURE0 + i);
                GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, 0);
            }
        }
        GLES32.glUseProgram(0);
        for(int error;(error = GLES32.glGetError()) != GLES32.GL_NO_ERROR;){
            GLLog.loge("error : " + error);
        }
    }
}
